热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CS20SI|Lecture4StructureyourTensorFlowmodel

前面一节中使用TensorFlow实现了简单的线性回归和逻辑斯谛回归。然而,复杂的模型是需要更好的总体设计,否则我们的模型将会变得非常混乱和很难调试。在接下来的两章中,将介绍如何有效地构建结构化

前面一节中使用TensorFlow实现了简单的线性回归和逻辑斯谛回归。然而,复杂的模型是需要更好的总体设计,否则我们的模型将会变得非常混乱和很难调试。在接下来的两章中,将介绍如何有效地构建结构化的模型。
本节将通过word2vec实例讲解。涉及到的部分NLP内容由于我本人理解有限所以就没有详细介绍,建议查阅相关资料
本文只记录了部分代码,完整代码请查看课程GitHub

Agenda
  • Overall structure of a model in TensorFlow
  • word2vec
  • Name scope
  • Embedding visualization

Overall structure of a model in TensorFlow

Phase 1: Assemble graph

  1. 定义输入输出的的容器placecholder
  2. 定义网络权值参数
  3. 定义推理模型
  4. 定义损失函数
  5. 定义优化器

Phase 2: Compute

Created with Raphaël 2.1.0 初始化模型参数 输入训练数据 在训练数据上执行推理 计算损失 调整模型参数

Word Embedding

通过词嵌入可以得到词语之间语义(semantic)上的关系
下图是使用TensorBoard中的t-SNE技术对词嵌入的结果进行可视化,可以看到和单词can语义相近的词语也均为情态动词。
词嵌入可视化

word2vec

wrod2vec是词嵌入的一种方式,具体内容可以参阅论文
Distributed Representations of Words and Phrases and their Compositionality
Efficient Estimation of Word Representations in Vector Space
我们需要词语的向量表示来输入到神经网络中进行后续的相关工作。
本章中使用skip-gram model构建word2vec。
Word2Vec Tutorial - The Skip-Gram Model
在skip-gram模型中,通过训练一个单隐层的神经网络来实现这个任务。但是我们关注的不是网络的输出,而是隐藏层的权重矩阵,这个权重矩阵就是我们需要的word vectorembedding matrix
在这个任务中,我们需要实现给定一句话中的中心词语(center word)来预测该词语附近的词语(上下文,语境)。
给定一个特定的词语,查找附近的词语并随机选择一个。神经网络会输出单词表中每一个词语出现在选定词语附近的概率。

Softmax, Negative Sampling, and Noise Contrastive Estimatio

这一小节主要介绍了word2vec的几种训练优化方式。
在CS224N(一门关于自然语言处理与深度学习的课程)中,讲过了两种训练方式:hierachical softmax(层次softmax)和 negative sampling。由于计算softmat函数需要进行归一化,这涉及了遍历词汇表中的所有单词,计算开销大,所以排除softmax的训练方式。在CS224N中,使用的是negative sampling + skip-gram model实现的word2vec。
Negative Sampling,负采样,是采样方法的一种,通过对样本进行采样来实现对原样本的近似。其他的还有importance sampling和target sampling。
个人理解NegativeSampling方法是通过在单词表中抽样部分单词作为负样本来代替总体,这样在计算损失的时候,只计算在这些抽样出的样本上的损失,而避免了遍历整个单词表,由于每次抽样都是随机的。多次抽样后的结果可以近似总体分布。每次只更新正确词语和抽样出的错误词语对应的权重。这种方法很适合当样本类别数量非常多的时候使用。TF里可以使用tf​.​nn​.​nce_loss实现。
Negative Sampling实际上是Noise Contrastive Estimation(NCE噪声对比估计)的一种简化版本,由于NCE还没有看,这里直接贴出一个简单解释

negative sampling makes certain assumption about the number of noise samples to generate (k) and the distribution of noise samples (Q) (negative sampling assumes that kQ(w) = 1) to simplify computation

相关文章
​On word embeddings - Part 2: Approximating the Softmax -Sebastian Rudder
NotesonNoiseContrastiveEstimationandNegativeSampling
Mikolov等在论文Distributed Representations of Words and Phrases and their Compositionality中提到使用Skip-gram model相比于复杂的hierarchical softmax来说能够更快的训练word2vec并在频繁出现的单词上获得更好的向量表示。
当噪音样本数量增加时,NCE具有negative sampling所缺乏的理论保证。Mnih and Teh(2012)说明了噪音样本数量取25的时候可以获得与常规softmax方法近似的表现,而训练速度却加快了约45倍。
在本章中,由于NCE具有理论保证,使用NCE方法实现word2vec。
最后注意,基于采样的方法只在训练过程中有用,在实际预测的时候,仍然需要用完整的softmax来获得归一化的概率。

About the Dataset

本节使用的数据集合是2006年3月3日的经过数据清洗的英语维基百科语料库中的前100MB部分。
然而100MB的训练数据其实并不能很好的训练出词向量,但是还是可以观察出一些有趣的现象。简单分词后大约有17,005,207个单词。
想要获得更好的结果,可以使用Matt Mahoney’s website​上的维基百科的dataset enwik9 的前10^9bytes 语料。

实战word2vec

Phase 1: Assemble the graph

  1. Define placeholders for input and output
    输入为中心词,输出为目标词(上下文中的)。这里直接使用单词下标而不是用one-hot 向量。我们对预料库进行预处理使得每一个单词都对应一个唯一的索引下标。所有输入输出均为一个标量数字scalar。

    center_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​])
    target_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​])

  2. Define the weight(embedding matrix)
    我们使用一个[VOCAB_SIZE,EMBED_SIZE]的矩阵来表示,该矩阵的每一行就是词语表中每个单词的词向量,每个词向量的大小为EMBED_SIZE。权重矩阵初始化为-1到1的均匀分布。
    embed_matrix ​=​ tf​.​Variable​(​tf​.​random_uniform​([​VOCAB_SIZE​,​ EMBED_SIZE​],​ ​-​1.0​,​ ​1.0​))

  3. Inference(计算图的前向计算)
    我们需要获得输入单词的词向量表示。事实上,对于一个独热编码后的单词输入来说,其向量与嵌入矩阵的乘积结果就是对应嵌入矩阵的某一行。也就是说,这里其实不需要做矩阵乘法运算,只需要选取对应的行即可。TF封装了tf​.​nn​.​embedding_lookup根据获取指定索引对应的词向量表示。
    这里写图片描述
    tf​.​nn​.​embedding_lookup​(​params​,​ ids​,​ partition_strategy​=​'mod'​,​ name​=​None​, validate_indices​=​True​,​ max_norm​=​None)
    embed ​=​ tf​.​nn​.​embedding_lookup​(​embed_matrix​,​ center_words)
  4. Define the loss function
    TF封装好了nce_loss
    tf​.​nn​.​nce_loss​(​weights​,​ biases​,​ labels​,​ inputs​,​ num_sampled​,​ num_classes​,​ num_true​=​1​, sampled_values​=​None​,​ remove_accidental_hits​=​False​,​ partition_strategy​=​'mod'​, name​=​'nce_loss')
    num_sampled参数是训练时用来作负样本的噪声单词的数量。
    具体实现

    nce_bias ​=​ tf​.​Variable​(​tf​.​zeros​([​VOCAB_SIZE​])) 
    loss ​=​ tf​.​reduce_mean​(​tf​.​nn​.​nce_loss​(​weights​=​nce_weight​,  biases​=​nce_bias​,  labels​=​target_words​,  inputs​=​embed​,  num_sampled​=​NUM_SAMPLED​,  num_classes​=​VOCAB_SIZE​)) 
  5. Define optimizer
    optimizer ​=​ tf​.​train​.​GradientDescentOptimizer​(​LEARNING_RATE​).​minimize​(​loss)

Phase 2: Execute the computation

with​ tf​.​Session​()​ ​as​ sess:     
    sess​.​run​(​tf​.​global_variables_initializer​()) 
    average_loss ​=​ ​0.0     ​
    batch ​=​ batch_gen​.​next​()         
    loss_batch​,​ _ ​=​ sess​.​run​([​loss​,​ optimizer​], feed_dict​={​center_words​:​ batch​[​0​],​ target_words​:​ batch​[​1​]})
    average_loss ​+=​ loss_batch         ​
    if​ ​(​index ​+​ ​1​)​ ​%​ ​2000​ ​==​ ​0:             
        ​print​(​'Average loss at step {}: {:5.1f}'​.​format​(​index ​+​ ​1​,average_loss ​/​ ​(​index ​+​ ​1​))) 

Name Scope

使用TensorBoard查看现在的网络结构
这里写图片描述
现在的结构图可读性很差,结点遍布在各个地方。TensorBoard不知道哪些结点具有相似的功能而应该被聚集在一起。如我们可以把与input/output相关的ops联系起来,与NCE loss相关的ops联系起来。TensorFlow提供了一种方式实现。

with​ tf​.​name_scope​(​name_of_that_scope​): 
    # declare op_1 
    # declare op_2 
    # ... 

举例来说,我们计算图可以分成3个op块,”Data”,”embed”,”NCE_LOSS”,

with​ tf​.​name_scope​(​'data'​):         
    center_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​],​ name​=​'center_words')         
    target_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​,​ ​1​],​ name​=​'target_words') 

with​ tf​.​name_scope​(​'embed'​):     
    embed_matrix ​=​ tf​.​Variable​(​tf​.​random_uniform​([​VOCAB_SIZE​,​ EMBED_SIZE​],​ ​-​1.0​,​ ​1.0​), name​=​'embed_matrix') 
with​ tf​.​name_scope​(​'loss'​):     
    embed ​=​ tf​.​nn​.​embedding_lookup​(​embed_matrix​,​ center_words​,​ name​=​'embed')     
    nce_bias ​=​ tf​.​Variable​(​tf​.​zeros​([​VOCAB_SIZE​]),​ name​=​'nce_bias')     
    loss ​=​ tf​.​reduce_mean​(​tf​.​nn​.​nce_loss​(​weights​=​nce_weight​, biases​=​nce_bias​,​ labels​=​target_words​,​ inputs​=​embed​, num_sampled​=​NUM_SAMPLED​,​ num_classes​=​VOCAB_SIZE​), name​=​'loss') 

看起来命名域embed似乎只有一个结点embed_matrix。事实上,它含有两个结点tf.Variabletf.random_uniform,使用上述代码再查看计算图,更加清晰易读。点击每一个op块的右上角的+号可以查看该块包含的ops
这里写图片描述
计算图中的实线表示数据流动的边。虚线表示依赖控制的边。如图中的loss依赖于init。控制依赖可以使用第2章讲的tf.Graph.control_dependencies(control_inputs)实现。
图例
这里写图片描述
完整流程

# Step 1: define the placeholders for input and output 
with​ tf​.​name_scope​(​"data"​):     
    center_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​],​ name​=​'center_words')     
    target_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​,​ ​1​],​ name​=​'target_words') 
with​ tf​.​device​(​'/cpu:0'​):     ​
    with​ tf​.​name_scope​(​"embed"​):         ​
        # Step 2: define weights. In word2vec, it's actually the weights that we care about
        embed_matrix ​=​ tf​.​Variable​(​tf​.​random_uniform​([​VOCAB_SIZE​,​ EMBED_SIZE​],​ ​-​1.0​,​ ​1.0​), name​=​'embed_matrix') 
     ​# Step 3 + 4: define the inference + the loss function with​ tf​.​name_scope​(​"loss"​): 
         ​# Step 3: define the inference
         embed ​=​ tf​.​nn​.​embedding_lookup​(​embed_matrix​,​ center_words​,​ name​=​'embed') 
         ​# Step 4: construct variables for NCE loss
         nce_weight ​=​ tf​.​Variable​(​tf​.​truncated_normal​([​VOCAB_SIZE​,​ EMBED_SIZE​],stddev​=​1.0​ ​/​ math​.​sqrt​(​EMBED_SIZE​)), name​=​'nce_weight')         
         nce_bias ​=​ tf​.​Variable​(​tf​.​zeros​([​VOCAB_SIZE​]),​ name​=​'nce_bias') 
         ​# define loss function to be NCE loss function
         loss ​=​ tf​.​reduce_mean​(​tf​.​nn​.​nce_loss​(​weights​=​nce_weight​,biases​=​nce_bias​,​ labels​=​target_words​, inputs​=​embed​,num_sampled​=​NUM_SAMPLED​, num_classes​=​VOCAB_SIZE​),​ name​=​'loss') 
     ​# Step 5: define optimizer 
     optimizer ​=​ tf​.​train​.​GradientDescentOptimizer​(​LEARNING_RATE​).​minimize​(​loss)

面向对象编程

为了提升代码的重用性,使用面向对象的思想

class​ ​SkipGramModel:""" Build the graph for word2vec model """def__init__(​self​,​ ​params​):pass 
    def_create_placeholders(​self​):""" Step 1: define the placeholders for input and output """passdef_create_embedding(​self​):""" Step 2: define weights. In word2vec, it's actually the weights that we care about """passdef_create_loss(​self​):""" Step 3 + 4: define the inference + the loss function """pass 
    def_create_optimizer(​self​):""" Step 5: define optimizer """pass

t-SNE

t​-​distributed stochastic neighbor embedding ​(​t​-​SNE​)​ ​is​ a machine learning algorithm ​for dimensionality reduction developed ​by​ ​Geoffrey​ ​Hinton​ ​and​ ​Laurens​ van der ​Maaten​.​ ​It​ ​is​ a nonlinear dimensionality reduction technique that ​is​ particularly well​-​suited ​for​ embedding high​-​dimensional data ​into​ a space of two ​or​ three dimensions​,​ which can ​then​ be visualized in​ a scatter plot​.​ ​Specifically​,​ it models each high​-​dimensional ​object​ ​by​ a two​-​ ​or three​-​dimensional point ​in​ such a way that similar objects are modeled ​by​ nearby points ​and dissimilar objects are modeled ​by​ distant points​.
The​ t​-​SNE algorithm comprises two main stages​.​ ​First​,​ t​-​SNE constructs a probability distribution over pairs of high​-​dimensional objects ​in​ such a way that similar objects have a high probability of being picked​,​ whilst dissimilar points have an extremely small probability of being picked​.​ ​Second​,​ t​-​SNE defines a similar probability distribution over the points ​in​ the low​-​dimensional map​,​ ​and​ it minimizes the ​Kullback​–​Leibler​ divergence between the two distributions ​with​ respect to the locations of the points ​in​ the map​.​ ​Note
that whilst the original algorithm uses the ​Euclidean​ distance between objects ​as​ the ​base of its similarity metric​,​ ​this​ should be changed ​as​ appropriate.

使用t-SNE技术可以将高维数据投影到2维或3维进行可视化,使得在高维空间中相近点在低维空间中也相近。TensorBoard提供了t-SNE和PCA两种可视化技术。
最后的可视化结果就是本文最开始的部分已经给出。
相关代码

from tensorflow.contrib.tensorboard.plugins import projector 

# 在训练好词向量后获取embed_matrix
final_embed_matrix ​=​ sess​.​run​(​model​.​embed_matrix) 
# 创建一个tf.Variable来容纳embeddings,这里不能用constans,也不能用之前模型里定义的embed_matrix.
# 获取前500个最流行的单词
embedding_var = tf.Variable(final_embed_matrix[:500],name='embedding') 
sess.run(embedding_var.initializer) 
cOnfig= projector.ProjectorConfig() 
summary_writer = tf.summary.FileWriter(LOGDIR) 

# 向config添加embedding
embedding = config.embeddings.add()
embedding.tensor_name = embedding_var.name 

# link the embeddings to their metadata file. In this case, the file that contains 
# the 500 most popular words in our vocabulary 
embedding.metadata_path = LOGDIR + '/vocab_500.tsv' 

# save a configuration file that TensorBoard will read during startup 
projector.visualize_embeddings(summary_writer, config) 

# save our embedding 
saver_embed = tf.train.Saver([embedding_var]) saver_embed.save(sess, LOGDIR + '/skip-gram.ckpt', 1) 


推荐阅读
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • cs231n Lecture 3 线性分类笔记(一)
    内容列表线性分类器简介线性评分函数阐明线性分类器损失函数多类SVMSoftmax分类器SVM和Softmax的比较基于Web的可交互线性分类器原型小结注:中文翻译 ... [详细]
  • 线程漫谈——线程基础
    本系列意在记录Windwos线程的相关知识点,包括线程基础、线程调度、线程同步、TLS、线程池等。进程与线程理解线程是至关重要的,每个进程至少有一个线程,进程是线程的容器,线程才是真正的执行体,线程必 ... [详细]
  • 安装Tensorflow-GPU文档第一步:通过Anaconda安装python从这个链接https:www.anaconda.comdownload#window ... [详细]
  • keras归一化激活函数dropout
    激活函数:1.softmax函数在多分类中常用的激活函数,是基于逻辑回归的,常用在输出一层,将输出压缩在0~1之间,且保证所有元素和为1,表示输入值属于每个输出值的概率大小2、Si ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
  • 本文介绍了Python语言程序设计中文件和数据格式化的操作,包括使用np.savetext保存文本文件,对文本文件和二进制文件进行统一的操作步骤,以及使用Numpy模块进行数据可视化编程的指南。同时还提供了一些关于Python的测试题。 ... [详细]
  • SpringMVC工作流程概述
    SpringMVC工作流程概述 ... [详细]
  • 本文探讨了容器技术在安全方面面临的挑战,并提出了相应的解决方案。多租户保护、用户访问控制、中毒的镜像、验证和加密、容器守护以及容器监控都是容器技术中需要关注的安全问题。通过在虚拟机中运行容器、限制特权升级、使用受信任的镜像库、进行验证和加密、限制容器守护进程的访问以及监控容器栈,可以提高容器技术的安全性。未来,随着容器技术的发展,还需解决诸如硬件支持、软件定义基础设施集成等挑战。 ... [详细]
  • 翻译 | 编写SVG的口袋指南(上)
    作者:DDU(沪江前端开发工程师)本文是原文翻译,转载请注明作者及出处。简介ScalableVectorGraphics(SVG)是在XML中描述二维图形的语言。这些图形由路径,图 ... [详细]
  • 震惊,正儿八经的网页居然在手机上这样显示!
    本篇文章所描述的,是网页移动端开发中的一些概念,以及一些常用标签~一、像素基本知识设备物理像素:设备上的一个像素点设备无关像素࿱ ... [详细]
  • 基于,docker,快速,部署,多,需求,spark ... [详细]
author-avatar
PrinceVince_820
这个家伙很懒,什么也没留下!
Tags | 热门标签
RankList | 热门文章
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有